package com.xiguthings.xiniu.iot.trigger.worker.trigger.calculation.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import com.xiguthings.xiniu.iot.trigger.worker.trigger.calculation.Engine;

public class SimpleEngine implements Engine {
	public SimpleEngine() {
		symbolPriority.put(AND, 5);
		symbolPriority.put(OR, 5);
		symbolPriority.put(ADD, 6);
		symbolPriority.put(SUB, 6);
		symbolPriority.put(MUL, 7);
		symbolPriority.put(DIV, 7);
		symbolPriority.put("(", 1);
		keyWordList.add(AND);
		keyWordList.add(OR);
		keyWordList.add("(");
		keyWordList.add(")");
		keyWordList.add("true");
		keyWordList.add("false");
	}

	@Override
	public boolean expressionCalculation(String expStr) throws Exception {
		expStr = formatter(expStr);
		boolean isLegal = inspectionLegal(expStr);
		if (isLegal) {
			boolean b = this.expBoolenValue(expStr);
			return b;
		}
		return false;

	}

	/**
	 * 将各式统一
	 * 
	 * @param expStr
	 * @return
	 */
	private String formatter(String expStr) {
		// 将所有的and和or小写的都转成大小的
		// expStr = expStr.toUpperCase();
		// expStr = expStr.replace("TRUE", "true");
		// expStr = expStr.replace("FALSE", "false");
		expStr = expStr.replaceAll("or", " OR ");
		expStr = expStr.replaceAll("and", " AND ");

		// 中文括号转英文括号
		expStr = expStr.replaceAll("（", "(");
		expStr = expStr.replaceAll("）", ")");

		// 在所有的and和or的前后都添加空格
		// expStr = expStr.replaceAll("OR", " OR ");
		// expStr = expStr.replaceAll("AND", " AND ");
		expStr = expStr.trim();
		return expStr;
	}

	/**
	 * 先简单的检查表达式是否合法
	 * 
	 * @param expStr
	 * @return
	 */
	private boolean inspectionLegal(String expStr) {

		return true;

	}

	private Vector<String> stack = new Vector<String>();
	private static final String AND = "AND";
	private static final String OR = "OR";
	private static final String ADD = "+";
	private static final String SUB = "-";
	private static final String MUL = "*";
	private static final String DIV = "/";
	private List<String> keyWordList = new ArrayList<String>();
	private Map<String, Integer> symbolPriority = new HashMap<String, Integer>();

	public boolean expBoolenValue(String exp) throws Exception {
		List<String> expList = validate(exp);
		List<String> suffixExpList = getSuffixExp(expList);
		String value = getValue(suffixExpList);
		stack.clear();
		return Boolean.parseBoolean(value);
	}

	public int expIntValue(String exp) throws Exception {
		String expf[] = exp.split(" ");
		List<String> expList = Arrays.asList(expf);
		List<String> suffixExpList = getSuffixExp(expList);
		String value = getValue(suffixExpList);
		stack.clear();
		return Integer.parseInt(value);
	}

	private List<String> validate(String inputExp) {
		inputExp = inputExp.replace(" ", "");
		List<String> outExpList = new ArrayList<String>();
		int preIndex = 0;
		int curIndex = 0;
		for (int i = 0; i < inputExp.length(); i++) {
			curIndex = i;
			String keyWord = inputExp.substring(preIndex, curIndex + 1);
			if (keyWordList.contains(keyWord)) {
				outExpList.add(keyWord);
				preIndex = curIndex + 1;
			}
		}
		return outExpList;
	}

	private List<String> getSuffixExp(List<String> expList) {
		List<String> suffixList = new ArrayList<String>();
		for (int i = 0; i < expList.size(); i++) {
			String word = expList.get(i);
			switch (word) {
			case "(":
				stack.add(word);
				break;
			case ")":
				Pop(suffixList, "(");
				break;
			case AND:
				push(suffixList, word);
				break;
			case OR:
				push(suffixList, word);
				break;
			case ADD:
				push(suffixList, word);
				break;
			case SUB:
				push(suffixList, word);
				break;
			case MUL:
				push(suffixList, word);
				break;
			case DIV:
				push(suffixList, word);
				break;
			default:
				suffixList.add(word);
				break;
			}
		}
		for (int i = stack.size() - 1; i >= 0; i--) {
			suffixList.add(stack.get(i));
		}
		return suffixList;
	}

	private String getValue(List<String> expList) {
		Vector<String> calcuVec = new Vector<String>();
		for (int i = 0; i < expList.size(); i++) {
			String word = expList.get(i);
			switch (word) {
			case AND:
				String andp1 = calcuVec.get(calcuVec.size() - 2);
				String andp2 = calcuVec.get(calcuVec.size() - 1);
				boolean andbp1 = Boolean.parseBoolean(andp1);
				boolean andbp2 = Boolean.parseBoolean(andp2);
				boolean andbp = andbp1 && andbp2;
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.add(Boolean.toString(andbp));
				break;
			case OR:
				String orp1 = calcuVec.get(calcuVec.size() - 2);
				String orp2 = calcuVec.get(calcuVec.size() - 1);
				boolean orbp1 = Boolean.parseBoolean(orp1);
				boolean orbp2 = Boolean.parseBoolean(orp2);
				boolean orbp = orbp1 || orbp2;
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.add(Boolean.toString(orbp));
				break;
			case ADD:
				String addp1 = calcuVec.get(calcuVec.size() - 2);
				String addp2 = calcuVec.get(calcuVec.size() - 1);
				int addbp1 = Integer.parseInt(addp1);
				int addbp2 = Integer.parseInt(addp2);
				int addbp = addbp1 + addbp2;
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.add(Integer.toString(addbp));
				break;
			case SUB:
				String subp1 = calcuVec.get(calcuVec.size() - 2);
				String subp2 = calcuVec.get(calcuVec.size() - 1);
				int subbp1 = Integer.parseInt(subp1);
				int subbp2 = Integer.parseInt(subp2);
				int subbp = subbp1 - subbp2;
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.add(Integer.toString(subbp));
				break;
			case MUL:
				String mulp1 = calcuVec.get(calcuVec.size() - 2);
				String mulp2 = calcuVec.get(calcuVec.size() - 1);
				int mulbp1 = Integer.parseInt(mulp1);
				int mulbp2 = Integer.parseInt(mulp2);
				int mulbp = mulbp1 * mulbp2;
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.add(Integer.toString(mulbp));
				break;
			case DIV:
				String divp1 = calcuVec.get(calcuVec.size() - 2);
				String divp2 = calcuVec.get(calcuVec.size() - 1);
				int divbp1 = Integer.parseInt(divp1);
				int divbp2 = Integer.parseInt(divp2);
				int divbp = divbp1 / divbp2;
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.remove(calcuVec.size() - 1);
				calcuVec.add(Integer.toString(divbp));
				break;
			default:
				calcuVec.add(word);
				break;
			}
		}
		return calcuVec.get(0);
	}

	private void Pop(List<String> suffixList, String endStr) {
		if (stack.isEmpty()) {
			return;
		}
		int i = stack.size() - 1;
		int j = stack.size();
		for (; i >= 0; i--) {
			String word = stack.get(i);
			if (word.equals(endStr)) {
				break;
			}
			suffixList.add(word);
		}
		for (int k = 0; k < j - i; k++) {
			int index = stack.size() - 1;
			stack.remove(index);
		}
	}

	private void push(List<String> suffixList, String word) {
		if (stack.isEmpty()) {
			stack.add(word);
			return;
		}
		// 符号入栈时，判断栈顶符号与入栈符号的优先级
		// 如果入栈符号的优先级大于栈顶符号，入栈
		String topEle = stack.get(stack.size() - 1);
		if (symbolPriority.get(word) > symbolPriority.get(topEle)) {
			stack.add(word);
		} else {
			// 弹出栈顶元素，直到栈顶元素的优先级比当前入栈的优先级高
			int i = stack.size() - 1;
			int j = stack.size();
			for (; i >= 0; i--) {
				String topE = stack.get(i);
				if (symbolPriority.get(topE) < symbolPriority.get(word))
					break;
				suffixList.add(topE);
			}
			if (i < 0)
				i = 0;
			for (int k = 0; k < j - i; k++) {
				int index = stack.size() - 1;
				stack.remove(index);
			}
			stack.add(word);
		}
	}

}
